import java.util.PriorityQueue;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: Home-pc
 * Date: 2023-09-28
 * Time: 14:55
 */
//创建一个类，用来描述定时器中的一个任务
class MyTimerTask implements Comparable<MyTimerTask> {
    //任务执行时间
    private long time;
    //具体任务
    private Runnable runnable;

    //构造函数
    public MyTimerTask(Runnable runnable,long delay) {
        this.time = System.currentTimeMillis()+delay;
        this.runnable = runnable;
    }
    public long getTime() {
        return time;
    }
    public Runnable getRunnable() {
        return runnable;
    }

    @Override
    public int compareTo(MyTimerTask o) {
        //时间小的任务，会被放置在队首
        return (int)(this.time-o.time);
    }
}

//定时器类的本体
class MyTimer{
    //创建一个优先级队列存储上述的N个任务
    private PriorityQueue<MyTimerTask> queue=new PriorityQueue<>();

    //用来加锁的对象
    private Object locker=new Object();

    //提供一个schedule方法，把要执行的任务添加到队列中去
    public void  schedule(Runnable runnable,long delay){
        //new 一个任务对象
        synchronized (locker){
            MyTimerTask task=new MyTimerTask(runnable,delay);
            queue.offer(task);
            //每次来新的任务，都唤醒之前的扫描线程，让扫描线程根据当前的任务情况，重新规划等待时间
            locker.notify();
        }
    }
    //构造函数 提供一个扫描线程，一方面去监控队首元素是否到执行时间了，另一方面，如果到了执行时间，这需要调用这里的Runable中的run方法来完成任务
    public MyTimer(){
        Thread t=new Thread(() ->{
           while(true){
               try {
                   synchronized (locker){
                       while(queue.isEmpty()){
                           //如果当前队列为空，就不应该去队列中取任务，使用wait进行等待，直到有任务加入队列
                           locker.wait();
                       }
                       //判断当前队列中的队首元素距离执行时间的时间差
                       MyTimerTask task=queue.peek();
                       long curTime=System.currentTimeMillis();
                       if(curTime>=task.getTime()){
                           //当前时间大于等于任务的执行时间，开始执行
                           queue.poll();//把已经执行的任务弹出队列
                           task.getRunnable().run();//执行任务
                       }else{
                           //没有到任务时间，扫描线程休眠时间差
                           //Thread.sleep(task.getTime()-curTime);
                           locker.wait(task.getTime()-curTime);
                       }
                   }
                   }catch (InterruptedException e) {
                   e.printStackTrace();
               }
           }
        });
        t.start();
    }

}

public class Demo21 {
    public static void main(String[] args) {
        MyTimer timer=new MyTimer();
        timer.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("hello 3");
            }
        },3000);

        timer.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("hello 2");
            }
        },2000);

        timer.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("hello 1");
            }
        },1000);
        System.out.println("程序开始运行");
    }
}
